<?php
/**
 *
 */
class Yz_Action_Update
    extends Yz_Action_Abstract
{

    /**
     *  @var array( fieldName: fieldSelectClause )
     */
    protected $fields = array();

    /** SQL rows limit, set to 1 for base Select to avoid occasionally selecting all rows
     *  @var int(1)
     */
    protected $limit = 1;

    protected $references = array();

    /**
     *  Update requires at least one field/value
     *  @var Item
     */
    protected $values;


    /************************************
     *          Public methods          *
     ************************************/

    // public function setValues($values)

    /***************************************
     *          Protected methods          *
     ***************************************/

    /** Verify any arguments before building query
     *  virtual method
     *  @return this
     */
    protected function verifyArguments()
    {
        debug();
        if (! $this->values) {
            throw StateError::_new_();
        }
        return $this;
    }


    /**
     *  Inspect model's property and create a field clause or
     *      recursively inspect referenced model
     *  @param Yz_Model_Interface $model
     *  @param string $name
     *  @param Yz_Model_Field_Interface $prop
     *  @return this
     */
    protected function inspectField(Yz_Model_Interface $model, $alias, $propName, Yz_Model_Field_Interface $prop)
    {
        debug();
        if ($prop instanceof Yz_Model_Field_Id) {
            // ### skip primary key
            $clause = false;
        } else if ($prop instanceof Yz_Model_Field_OneToOne) {
            $clause = false;
        } else if ($prop instanceof Yz_Model_Field_Reference) {
            // ### handle referenced items
            $this->references[] = $propName;
            $clause = ":{$propName}";
            $propName .= 'Id';
        } else {
            $clause = ":{$propName}";
        }

        if ($clause) {
            $modelName = $model->getName();

            // TODO check custom settings for the field
            $fieldSpec = "{$modelName}.{$propName}";

            $this->fields[$fieldSpec] = $clause;

        }
        return $this;
    }


    /**
     *  Common UPDATE statement creator:
     *      the common part of statement
     *  @return Yz_SQL_Statement_Update
     */
    protected function buildStatement()
    {
        debug();
        $this->inspectModel();
        return Yz_SQL_Statement_Update::create()
            ->update($this->tables)
            ->set($this->fields)
        ;
    }


    /** Inspect a model and determine what (fields) and from where (tables) will be selected
     *  @param Yz_Model_Interface $model
     *  @param string $alias
     *  @return Yz_Array fields
     */
    protected function doInspectModel(Yz_Model_Interface $model, $alias)
    {
        debug();
        $origModel = $model;
        while ($parent = $model->getParentModel()) {
            // recursively add sources for parent models
            $this
                ->addParentSource($model, $parent)
                ->doInspectModel($parent, $parent->getName())
            ;
            $model = $parent;
        }
        return parent::doInspectModel($origModel, $alias);
    }


    /** Add the parent model's table to table list
     *  @param $origModel
     *  @param $parentModel
     */
    protected function addParentSource($origModel, $parentModel)
    {
        debug("Add Parent {$parentModel}");
        $parentAlias = $parentModel->getName();
        $this->tables[$parentAlias] = Yz_SQL_Join::innerJoin(
            $parentModel->getSourceName(),
            $parentAlias
        )->joinUsing('id');
        return $this;
    }

}
